﻿using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Text;

namespace StockTools.Model
{
    /// <summary>
    /// 买入数据
    /// </summary>
    public class BuyingDataModel : BindableBase
    {
        private decimal buyPrice;
        private int buyNumber;
        private string code;
        private decimal amount;
        private decimal brokerage;
        private decimal transferMoney;
        private decimal totalFee;
        private decimal payAmount;
        private decimal buyingCost;
        private decimal breakevenPrice;

        /// <summary>
        /// 股票代码
        /// </summary>
        public string Code { get => code; set => SetProperty(ref code, value); }
        /// <summary>
        /// 买入数量
        /// </summary>
        public int BuyNumber { get => buyNumber; set => SetProperty(ref buyNumber, value); }
        /// <summary>
        /// 买入价格
        /// </summary>
        public decimal BuyPrice { get => buyPrice; set => SetProperty(ref buyPrice, value); }

        /// <summary>
        /// 交易金额
        /// </summary>
        public decimal Amount { get => amount; set => SetProperty(ref amount, value); }
        /// <summary>
        /// 佣金
        /// </summary>
        public decimal Brokerage { get => brokerage; set => SetProperty(ref brokerage, value); }
        /// <summary>
        /// 过户费
        /// </summary>
        public decimal TransferMoney { get => transferMoney; set => SetProperty(ref transferMoney, value); }
        /// <summary>
        /// 总手续费
        /// </summary>
        public decimal TotalFee { get => totalFee; set => SetProperty(ref totalFee, value); }
        /// <summary>
        /// 实付金额
        /// </summary>
        public decimal PayAmount { get => payAmount; set => SetProperty(ref payAmount, value); }
        /// <summary>
        /// 买入成本
        /// </summary>
        public decimal BuyingCost { get => buyingCost; set => SetProperty(ref buyingCost, value); }

        /// <summary>
        /// 保本价格
        /// </summary>
        public decimal BreakevenPrice { get => breakevenPrice; set => SetProperty(ref breakevenPrice, value); }

        /// <summary>
        /// 计算
        /// </summary>
        /// <param name="rateSetting"></param>
        internal void Compute(RateSettingModel rateSetting)
        {
            if (this.buyNumber == 0) return;

            this.Amount = Math.Round(BuyPrice * BuyNumber, 2);

            this.Brokerage = ComputeBrokerage(this.Amount, rateSetting);

            this.TransferMoney = ComputeTransferMoney(rateSetting);

            TotalFee = this.Brokerage + this.TransferMoney;
            PayAmount = this.Amount + TotalFee;

            BuyingCost = Math.Round(PayAmount / BuyNumber, 4);
            BreakevenPrice = ComputeBreakevenPrice(BuyingCost, rateSetting);

        }

        /// <summary>
        /// 计算佣金
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="rateSetting"></param>
        /// <returns></returns>
        private decimal ComputeBrokerage(decimal amount, RateSettingModel rateSetting)
        {
            var brokerage = Math.Round(amount * rateSetting.BuyBrokerageRatio * 0.001M, 2, MidpointRounding.ToPositiveInfinity);
            if (brokerage < 5)
                brokerage = rateSetting.MinBrokerageRatio;
            return brokerage;
        }
        /// <summary>
        /// 计算过户费
        /// </summary>
        /// <param name="rateSetting"></param>
        /// <returns></returns>
        private decimal ComputeTransferMoney(RateSettingModel rateSetting)
        {
            decimal output;
            if (!Code.IsNullOrEmpty() && Code.StartsWith("6"))
            {
                output = Math.Round(rateSetting.TransferMoney / 1000 * BuyNumber, 2, MidpointRounding.ToPositiveInfinity);
                if (output < rateSetting.MinTransferMoney)
                    output = rateSetting.MinTransferMoney;
            }
            else
            {
                output = 0;
            }
            return output;
        }
        /// <summary>
        /// 计算印花税
        /// </summary>
        /// <param name="money"></param>
        /// <param name="rateSetting"></param>
        /// <returns></returns>
        private decimal ComputeStampDuty(decimal money, RateSettingModel rateSetting)
        {
            var t = money * rateSetting.StampDuty * 0.001M;
            if (t < rateSetting.MinStampDuty)
                t = rateSetting.MinStampDuty;
            return t;
        }
        /// <summary>
        /// 计算保本价
        /// </summary>
        /// <param name="buyingCost"></param>
        /// <param name="rateSetting"></param>
        /// <returns></returns>
        private decimal ComputeBreakevenPrice(decimal buyingCost, RateSettingModel rateSetting)
        {
            decimal newCost = buyingCost;
            decimal newAmountActually = 0;//实收金额
            do
            {
                newCost = newCost + 0.01M;//每次加一分钱
                var yj = ComputeBrokerage(newCost * this.BuyNumber, rateSetting);
                var ghf = ComputeTransferMoney(rateSetting);
                var yhs = ComputeStampDuty(newCost * this.BuyNumber, rateSetting);

                newAmountActually = newCost * this.BuyNumber - yj - ghf - yhs;

            } while (this.PayAmount > newAmountActually);

            return Math.Round(newCost, 2, MidpointRounding.ToPositiveInfinity);
        }
    }
}